/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ch.hslu.prg2.team2.gui;

import ch.hslu.prg2.team2.entity.Disc;
import ch.hslu.prg2.team2.logic.ComputerPlayer;
import ch.hslu.prg2.team2.logic.GameEndEventType;
import ch.hslu.prg2.team2.logic.Gameboard;
import ch.hslu.prg2.team2.logic.GameboardSerializer;
import ch.hslu.prg2.team2.logic.IGameEndEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 *
 * @author Stefan Bieri
 * @version 1.0.1
 */
public class MainFrame extends JFrame 
{
    private JButton[] button;
    private JPanel[][] field;

    private JLabel statusField;
    private Gameboard gameboard;
    private MainFrame mainFrame;

    public MainFrame(Gameboard gameboard) 
    {
        super("Vier gewinnt");
        
        mainFrame = this;
        
        setResizable(true);
        setLocation(500, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.gameboard = gameboard;        
        DrawGameboard();

        pack();
        updateButtonsAndField();
    }

    private void DrawGameboard()
    {
        gameboard.registerGameEndEvents(new GameEndEventListener());
        button = new JButton[gameboard.getColumnCount()];
        field = new JPanel[gameboard.getRowCount()][gameboard.getColumnCount()];
        setLayout(new BorderLayout());
        JPanel panelCenter = new JPanel(new GridLayout(gameboard.getRowCount() + 1, gameboard.getColumnCount()));
        JPanel panelNorth = new JPanel();
        statusField = new JLabel();
        statusField.setText("Spiel gegen " + gameboard.getComputerPlayer() + " läuft");
        statusField.setHorizontalAlignment(SwingConstants.CENTER);
        panelNorth.add(statusField);
        getContentPane().removeAll();
        getContentPane().add(BorderLayout.NORTH, panelNorth);
        // Button oberhalb der Spalten anlegen
        for (int i = 0; i < gameboard.getColumnCount(); i++)
        {
            button[i] = new JButton("Stein spielen");
            button[i].setSize(50, 20);
            button[i].addActionListener(new ColumnButtonListener(i));
            panelCenter.add (button[i]);
        }
        // Felder anlegen
        for (int r = 0; r < gameboard.getRowCount(); ++r)
        {
            for (int c = 0; c < gameboard.getColumnCount(); ++c)
            {
                field[r][c] = new JPanel();
                field[r][c].setBorder(BorderFactory.createLineBorder(Color.WHITE));
                field[r][c].setForeground(Color.WHITE);
                field[r][c].setPreferredSize(new Dimension(100, 60));
                panelCenter.add(field[r][c]);
            }
        }
        
        panelCenter.setBackground(Color.DARK_GRAY);
        getContentPane().add(BorderLayout.CENTER, panelCenter);
        
        /* Bind menu settings */
        JMenuItem menuitemReset = new JMenuItem("Neues Spiel");
        menuitemReset.addActionListener(new ButtonStartListener());

        JMenu menuFile = new JMenu("Datei");
        menuFile.add(menuitemReset);
        menuFile.addSeparator();
        JMenuItem menuitemOpen = new JMenuItem("Öffnen...");
        JMenuItem menuitemSave = new JMenuItem("Speichern...");
        menuFile.add(menuitemOpen);
        menuFile.add(menuitemSave);
        menuFile.addSeparator();
        JMenuItem menuitemClose = new JMenuItem("Beenden");
        menuitemClose.addActionListener(new ButtonAbortListener());
        menuFile.add(menuitemClose);
        
        JMenuItem menuitemOpponent = new JMenuItem("Computerspieler...");
        menuitemOpponent.addActionListener(new OpponentChangeListener());
        JMenu menuOptions = new JMenu("Optionen");
        menuOptions.add(menuitemOpponent);
        
        JMenuItem menuitemGameboardSize = new JMenuItem("Spielfeldgrösse...");
        menuitemGameboardSize.addActionListener(new GameboardSizeChangeListener());
        menuOptions.add(menuitemGameboardSize);        
        
        menuitemSave = new JMenuItem("Speichern...");
        menuitemSave.addActionListener(new SaveGameListener(gameboard));
        menuitemOpen.addActionListener(new OpenGameListener(this));

        JMenuBar menubar = new JMenuBar();
        menubar.add(menuFile);
        menubar.add(menuOptions);
        setJMenuBar(menubar);
        
        JPanel panelSouth = new JPanel();
        JButton buttonStartGame = new JButton("Neues Spiel");
        JButton buttonAbortGame = new JButton("Beenden");
        buttonStartGame.addActionListener(new ButtonStartListener());
        buttonAbortGame.addActionListener(new ButtonAbortListener());
        panelSouth.add(buttonStartGame);
        panelSouth.add(buttonAbortGame);        
        
        getContentPane().add(BorderLayout.SOUTH, panelSouth);
        
        pack();
        repaint();
    }

    private void updateButtonsAndField() {
        updateButtons();
        updateField();
    }

    private void updateButtons() {
        for (int i = 0; i < gameboard.getColumnCount(); i++) {
            if (gameboard.isColumnPlayable(i)) {
                button[i].setEnabled(true);
            } else {
                button[i].setEnabled(false);
            }
        }
    }

    private void updateField() {
        for (int i = 0; i < gameboard.getRowCount(); i++) {
            for (int j = 0; j < gameboard.getColumnCount(); j++) {
                Disc disc = gameboard.getDisc(i, j);
                if (disc == null) {
                    field[i][j].setBackground(Color.DARK_GRAY);
                } else if (disc.getPlayer().getName().equals("User")) {
                    field[i][j].setBackground(Color.BLUE);
                } else {
                    field[i][j].setBackground(Color.RED);
                }
            }
        }
    }

    private void startNewGame(Gameboard gameboard) 
    {        
        this.gameboard = gameboard;
        this.gameboard.registerGameEndEvents(new GameEndEventListener());
        updateButtonsAndField();
        statusField.setText("Spiel gegen " + this.gameboard.getComputerPlayer() + " läuft");
    }
    
    private void paintLastDisc(int row, int col)
    {
        field[row][col].setBackground(Color.ORANGE);
    }
    
    public void setGameboard( Gameboard gameboard )
    {
        this.gameboard = gameboard;
    }

    public class ButtonStartListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            Gameboard newGameboard = new Gameboard(gameboard.getRowCount(), gameboard.getColumnCount(), gameboard.getComputerPlayer());
            startNewGame(newGameboard);
        }
    }
    
    public class ButtonAbortListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            int reply = JOptionPane.showConfirmDialog(null, "Wollen Sie wirklich das Spiel beenden?", "Spiel beenden?", JOptionPane.YES_NO_OPTION);
            if (reply == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }
    }

    public class ColumnButtonListener implements ActionListener {

        private final int col;

        public ColumnButtonListener(int col) {
            this.col = col;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            gameboard.playDisc(col);
            if( gameboard.isRunning())
            {
                updateButtonsAndField();
            }
            else
            {
                updateButtons();
            }
        }
    }

    public class GameEndEventListener implements IGameEndEvent {

        @Override
        public void gameEnded(GameEndEventType type, int lastCol) {         
            if( type != GameEndEventType.FieldFull )
            {
                for( int i=0; i < gameboard.getRowCount(); i++ )
                {
                    if( gameboard.getDisc(i, lastCol) != null )
                    {
                        paintLastDisc(i,lastCol);                    
                        break;
                    }
                }
                
                if( type == GameEndEventType.PlayerWon )
                {
                    statusField.setText("Spiel gewonnen!");
                }
                else if( type == GameEndEventType.ComputerPlayerWon )
                {
                    statusField.setText("Spiel verloren!");
                }
            }
            else
            {
                statusField.setText("Spiel unentschieden.");
            }
        }
    }
    
    public class OpponentChangeListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            OpponentChangeDialog dlg = new OpponentChangeDialog(mainFrame);
            dlg.setComputerPlayerChangedListener(new ComputerPlayerChangedListener());
            dlg.setVisible(true);
        } 
        
        public class ComputerPlayerChangedListener implements IComputerPlayerChanged
        {
            @Override
            public void computerPlayerChanged(ComputerPlayer computerPlayer)
            {
                Gameboard newGameboard = new Gameboard(gameboard.getRowCount(), gameboard.getColumnCount(), computerPlayer);                
                startNewGame(newGameboard);
            }                        
        }
    }
    
    public class GameboardSizeChangeListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e )
        {
            GameboardSizeDialog dlg = new GameboardSizeDialog(mainFrame, gameboard.getRowCount(), gameboard.getColumnCount());
            dlg.setGameboardSizeChangedListener(new GameboardSizeChangedListener());
            dlg.setVisible(true);
        }
        
        public class GameboardSizeChangedListener implements IGameboardSizeChanged
        {
            @Override
            public void gameboardSizeChanged(int rows, int cols )
            {
                Gameboard newGameboard = new Gameboard( rows, cols, gameboard.getComputerPlayer());
                gameboard = newGameboard;                  
                DrawGameboard();
                startNewGame(newGameboard);
                mainFrame.repaint();
            }
        }
    }
    
    public class SaveGameListener implements ActionListener
    {
        private Gameboard gameboard;
        
        public SaveGameListener(Gameboard gameboard )
        {
            this.gameboard = gameboard;
        }
        
        @Override
        public void actionPerformed(ActionEvent e )
        {
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setDialogTitle("Spiel speichern");
            fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
            fileChooser.setFileFilter(new FileNameExtensionFilter("Vier Gewinnt Datei (*.bin)", "bin" ));
            int returnValue = fileChooser.showSaveDialog(mainFrame);

            if (returnValue == JFileChooser.APPROVE_OPTION)
            {
                File file = fileChooser.getSelectedFile();
                String filePath = file.getAbsolutePath();
                if( !filePath.endsWith(".bin"))
                {
                    filePath = filePath.concat(".bin");
                }
                
                GameboardSerializer serializer = new GameboardSerializer();
                serializer.serialize(gameboard, filePath);
            }
        }
    }
    
    public class OpenGameListener implements ActionListener
    {
        private MainFrame mainFrame;
        
        public OpenGameListener( MainFrame mainFrame )
        {
            this.mainFrame = mainFrame;
        }
        
        @Override
        public void actionPerformed(ActionEvent e )
        {
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setDialogTitle("Spiel laden");
            fileChooser.setFileFilter(new FileNameExtensionFilter("Vier Gewinnt Datei (*.bin)", "bin" ));
            int returnValue = fileChooser.showOpenDialog(mainFrame);

            if (returnValue == JFileChooser.APPROVE_OPTION) 
            {
                File file = fileChooser.getSelectedFile();
                
                GameboardSerializer serializer = new GameboardSerializer();
                Gameboard gameboard = serializer.deserialize(file.getAbsolutePath());
                mainFrame.setGameboard(gameboard);
                gameboard.registerGameEndEvents(new GameEndEventListener());
                mainFrame.updateButtonsAndField();
            }
        }
    }
}
